package com.wind.plugin.annotator;

import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.wind.plugin.configuration.PluginSettingsState;
import org.jetbrains.annotations.NotNull;

import java.util.List;

import static com.wind.plugin.common.Constant.textCurAttributesClass;

/**
 * @author wind 针对于行里包含特定字段的代码，整行高亮
 * @version 1.0
 * @description: TODO
 * @date 2025/2/7 13:46
 */
public class JavaClassesAnnotator implements Annotator {


    private static final String THREAD_LOCAL_CLASS = "java.lang.ThreadLocal";

    @Override
    public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {

        // 检查是否为引用表达式
        if (element instanceof PsiReferenceExpression) {
            PsiReferenceExpression ref = (PsiReferenceExpression) element;
            checkAndAnnotate(ref.resolve(), holder, ref);
        }

        // 检查是否为类创建表达式
        if (element instanceof PsiNewExpression) {
            PsiJavaCodeReferenceElement ref = ((PsiNewExpression) element).getClassReference();
            if (ref != null) {
                PsiElement resolved = ref.resolve();
                checkAndAnnotate(resolved, holder, element);
            }
        }

        // 检查是否为变量声明
        if (element instanceof PsiLocalVariable || element instanceof PsiField) {
            PsiVariable variable = (PsiVariable) element;
            PsiType type = variable.getType();
            // 新增对类型元素的处理
            PsiTypeElement typeElement = variable.getTypeElement();
            if (typeElement != null && isThreadLocalType(type)) {
                // 对类型元素本身创建注解（而不仅是变量名）
                createAnnotation(holder, typeElement);
            }

            // 保留原有对变量名的检查（可选）
            if (variable.getNameIdentifier() != null && isThreadLocalType(type)) {
                createAnnotation(holder, variable.getNameIdentifier());
            }
        }

        // 检查是否为方法调用
        if (element instanceof PsiMethodCallExpression) {
            PsiMethodCallExpression methodCall = (PsiMethodCallExpression) element;
            PsiReferenceExpression methodExpression = methodCall.getMethodExpression();
            PsiElement resolvedMethod = methodExpression.resolve();
            if (resolvedMethod instanceof PsiMethod) {
                // 检查返回类型是不是 ThreadLocal 或其子类
                PsiMethod method = (PsiMethod) resolvedMethod;
                PsiType returnType = method.getReturnType();
                if (isThreadLocalType(returnType)) {
                    createAnnotation(holder, element);
                }
                // 新增: 检查方法调用的实例是否为 ThreadLocal 或其子类
                PsiExpression qualifierExpression = methodCall.getMethodExpression().getQualifierExpression();
                if (qualifierExpression instanceof PsiReferenceExpression) {
                    PsiElement resolvedQualifier = ((PsiReferenceExpression) qualifierExpression).resolve();
                    if (resolvedQualifier instanceof PsiVariable) {
                        PsiVariable variable = (PsiVariable) resolvedQualifier;
                        PsiType type = variable.getType();
                        if (isThreadLocalType(type)) {
                            createAnnotation(holder, element);
                        }
                    }
                }
            }
        }

    }

    private void checkAndAnnotate(PsiElement resolved, AnnotationHolder holder, PsiElement element) {
        if (resolved instanceof PsiClass) {
            PsiClass psiClass = (PsiClass) resolved;
            if (isTargetClass(psiClass)  || isImplementerOfAny(psiClass)) {
                createAnnotation(holder, element);
            }
        }
    }


    // 修改检查逻辑
    private boolean isTargetClass(PsiClass psiClass) {
        PluginSettingsState settings = PluginSettingsState.getInstance();
        return settings.getHighlightClasses().contains(psiClass.getQualifiedName()) ||
                isSubclassOfAny(psiClass, settings.getHighlightClasses());
    }

    // 新增接口实现检查方法
    private boolean isImplementerOfAny(PsiClass psiClass) {
        PluginSettingsState settings = PluginSettingsState.getInstance();
        List<String> targetInterfaces = settings.getHighlightClasses();
        for (PsiClass implementedInterface : psiClass.getInterfaces()) {
            // 检查直接实现的接口
            if (targetInterfaces.contains(implementedInterface.getQualifiedName())) {
                return true;
            }
            // 递归检查继承的父接口
            if (isImplementerOfAny(implementedInterface)) {
                return true;
            }
        }
        // 检查父类的接口继承
        PsiClass superClass = psiClass.getSuperClass();
        return superClass != null && isImplementerOfAny(superClass);
    }

    private boolean isSubclassOfAny(PsiClass psiClass, List<String> targetClasses) {
        for (String className : targetClasses) {
            PsiClass target = JavaPsiFacade.getInstance(psiClass.getProject())
                    .findClass(className, GlobalSearchScope.allScope(psiClass.getProject()));
            if (target != null && psiClass.isInheritor(target, true)) {
                return true;
            }
        }
        return false;
    }


    private boolean isThreadLocalType(PsiType type) {
        if (type instanceof PsiClassType) {
            PsiClassType classType = (PsiClassType) type;
            PsiClass psiClass = classType.resolve();
            if (psiClass != null) {
                PluginSettingsState settings = PluginSettingsState.getInstance();
                return settings.getHighlightClasses().contains(psiClass.getQualifiedName()) ||
                        isSubclassOfAny(psiClass, settings.getHighlightClasses());
            }
        }
        return false;
    }

    private void createAnnotation(AnnotationHolder holder, PsiElement element) {
        Annotation annotation = holder.createAnnotation(HighlightSeverity.WARNING,
                element.getTextRange(),
                "代码评审注意项");
        annotation.setEnforcedTextAttributes(textCurAttributesClass);
    }
}
